import java.util.*;

/**
 * This little class is used to hold the catalog information about a database table.
 * A bunch of these objects in a Map <String, TableData> is used to store the catalog.
 */

class TableData implements Cloneable {

	private int tupleCount;
	private Map<String, AttInfo> attributes;

	public TableData(int numTuples, Map<String, AttInfo> attsIn)
	{
		tupleCount = numTuples;
		attributes = attsIn;
	}
	
	/**
	 * Clones this TableData.
	 */
	public TableData clone()
	{
		Map<String, AttInfo> clonedAttributes = new HashMap<String, AttInfo>();
		for (Map.Entry<String, AttInfo> attEntry : attributes.entrySet())
		{
			clonedAttributes.put(attEntry.getKey(), attEntry.getValue().clone());
		}
		return new TableData(this.tupleCount, clonedAttributes);
	}

	public int getTupleCount()
	{
		return tupleCount;
	}

	public AttInfo getAttInfo(String aboutMe)
	{
		return attributes.get(aboutMe);
	}
	
	/**
	 * Converts the attributes for this data into a format
	 * that is usable for an RA operation.
	 * @return
	 */
	public ArrayList<Attribute> getTableLayout() {
		ArrayList<Attribute> al = new ArrayList<Attribute>();
		int numAtts = attributes.size();
		for(int i = 0; i < numAtts; i++)
		{
			al.add(null);
		}
		for(Map.Entry<String, AttInfo> att : attributes.entrySet())
		{
			AttInfo ai = att.getValue();
			int seqNum = ai.getAttSequenceNumber();
			al.set(seqNum, new Attribute(ai.getDataType(), att.getKey()));
		}
		return al;
	}
	
	/**
	 * Converts the attributes for this data into a format
	 * that is usable for an RA operation with dot notation
	 * changed to underscores.
	 * @param correlation
	 * @return
	 */
	public ArrayList<Attribute> getTableLayout(String correlation) {
		ArrayList<Attribute> layout = new ArrayList<Attribute>();
		int numAtts = attributes.size();
		
		for(int i = 0; i < numAtts; i++)
		{
			layout.add(null);
		}
		
		for(Map.Entry<String, AttInfo> att : attributes.entrySet())
		{
			AttInfo ai = att.getValue();
			int seqNum = ai.getAttSequenceNumber();
			layout.set(seqNum, new Attribute(ai.getDataType(), correlation + "_" + att.getKey()));
		}
		
		return layout;
	}
	
	public ArrayList<Expression> getSelectList(String correlation) {
		if (correlation == null)
			throw new RuntimeException("TableData getSelectList received null correlation.");
		ArrayList<Expression> select = new ArrayList<Expression>();
		int numAtts = attributes.size();
		for (int i = 0; i < numAtts; i++)
			select.add(null);
		for (Map.Entry<String, AttInfo> att : attributes.entrySet()) {
			AttInfo ai = att.getValue();
			//Expression e = new Expression(ai.getDataType());
			Expression e = new Expression("identifier");
			e.setValue(correlation + "." + att.getKey());
			select.set(ai.getAttSequenceNumber(), e);
		}
		return select;
	}

	String print() {
		String res = tupleCount + " tuples; atts are {";
		for (Map.Entry<String, AttInfo> j : attributes.entrySet ()) {
			res += "(" + j.getKey () + ": " + j.getValue().print () + ")";
		}
		res += "}";
		return res;
	}

	public void joinMerge(TableData tableData)
	{
		for(Map.Entry<String, AttInfo> entry : this.attributes.entrySet())
		{
			String attribute = entry.getKey();
			AttInfo ai = entry.getValue();
			ai.joinMerge(tableData.getAttInfo(attribute));
		}
	}

	public void setAttributeMaxCard(long card)
	{
		for(AttInfo ai : attributes.values())
		{
			if(ai.getNumDistinctVals() > card)
			{
				ai.setNumDistinctVals(card);
			}
		}
	}

}